#include "scope.h"


// div = 1000000.0 * SCOPE_DIV_POINT_NUM * step / rate;
// rate = 1000000.0 * SCOPE_DIV_POINT_NUM * step / div;
// step = 1.0 * rate * div / 1000000.0 / SCOPE_DIV_POINT_NUM
int scope_helper_index_to_value(int index) 
{
    if (index <= 1) {
        return 1;
    }
    int rate = pow(10, index / 3);
    if ((index % 3) == 1) {
        rate = rate * 2;
    }
    if ((index % 3) == 2) {
        rate = rate * 5;
    }
    return rate;
}
   
int scope_helper_value_to_index_round_up(int rate) 
{
    for (int index = 1; index < 1000; index++) {
        int value = scope_helper_index_to_value(index);
        if (value >= rate) {
            return index;
        }
    }
}

int scope_helper_value_to_index_round_down(int rate) 
{    
    for (int index = 1; index < 1000; index++) {
        int value = scope_helper_index_to_value(index);
        if (value > rate) {
            return index - 1;
        }
    }
}

int scope_helper_get_step(void)
{
    return 256.0 * g_scope_cfg.rate * g_scope_cfg.time_div_us / 1000000.0 / SCOPE_DIV_POINT_NUM;
}

void __no_inline_not_in_flash_func(scope_helper_buffer_cali_data)(scope_snap_info *info)
{   
    // 预先缓存常用的变量，减少重复访问全局变量的开销
    const uint32_t length = info->length;
    scope_snap_data *data = info->buffer;
    
    const uint32_t ch0_scale = g_scope_cfg.ch0_scale;
    const scope_cali_ch *ch0 = &g_scope_cfg.cali_data.ch[0];
    const int ch0_gnd = ch0->gnd[ch0_scale];
    const int ch0_scale_val = ch0->scale[ch0_scale];
    
    const uint32_t ch1_scale = g_scope_cfg.ch1_scale;
    const scope_cali_ch *ch1 = &g_scope_cfg.cali_data.ch[1];
    const int ch1_gnd = ch1->gnd[ch1_scale];
    const int ch1_scale_val = ch1->scale[ch1_scale];

    // 使用指针遍历优化访问效率
    scope_snap_data * const data_end = data + length;
    for (; data < data_end; data++) {
        // 通道0校准
        data->ch0_min = (data->ch0_min - ch0_gnd) * ch0_scale_val;
        data->ch0_max = (data->ch0_max - ch0_gnd) * ch0_scale_val;

        // 通道1校准
        data->ch1_min = (data->ch1_min - ch1_gnd) * ch1_scale_val;
        data->ch1_max = (data->ch1_max - ch1_gnd) * ch1_scale_val;
    }
}

static void scope_helper_correct(void)
{
    if (g_scope_cfg.trigger_chnl == 0) {
        if (g_scope_cfg.ch0_gnd_mv >= g_scope_cfg.ch0_div_mv * SCOPE_TIME_DIV_NUM / 2) {
            g_scope_cfg.ch0_gnd_mv = g_scope_cfg.ch0_div_mv * (SCOPE_TIME_DIV_NUM / 2 - 1);
        }
        if (g_scope_cfg.ch0_gnd_mv <= -g_scope_cfg.ch0_div_mv * SCOPE_TIME_DIV_NUM / 2) {
            g_scope_cfg.ch0_gnd_mv = -g_scope_cfg.ch0_div_mv * (SCOPE_TIME_DIV_NUM / 2 - 1);
        }
        if (g_scope_cfg.trigger_level_mv + g_scope_cfg.ch0_gnd_mv >= g_scope_cfg.ch0_div_mv * SCOPE_TIME_DIV_NUM / 2) {
            g_scope_cfg.trigger_level_mv = g_scope_cfg.ch0_div_mv * (SCOPE_TIME_DIV_NUM / 2 - 1) - g_scope_cfg.ch0_gnd_mv;
        }
        if (g_scope_cfg.trigger_level_mv + g_scope_cfg.ch0_gnd_mv <= -g_scope_cfg.ch0_div_mv * SCOPE_TIME_DIV_NUM / 2) {
            g_scope_cfg.trigger_level_mv = -g_scope_cfg.ch0_div_mv * (SCOPE_TIME_DIV_NUM / 2 - 1) - g_scope_cfg.ch0_gnd_mv;
        }
    }
    if (g_scope_cfg.trigger_chnl == 1) {
        if (g_scope_cfg.ch1_gnd_mv >= g_scope_cfg.ch1_div_mv * SCOPE_TIME_DIV_NUM / 2) {
            g_scope_cfg.ch1_gnd_mv = g_scope_cfg.ch1_div_mv * (SCOPE_TIME_DIV_NUM / 2 - 1);
        }
        if (g_scope_cfg.ch1_gnd_mv <= -g_scope_cfg.ch1_div_mv * SCOPE_TIME_DIV_NUM / 2) {
            g_scope_cfg.ch1_gnd_mv = -g_scope_cfg.ch1_div_mv * (SCOPE_TIME_DIV_NUM / 2 - 1);
        }
        if (g_scope_cfg.trigger_level_mv + g_scope_cfg.ch1_gnd_mv >= g_scope_cfg.ch1_div_mv * SCOPE_TIME_DIV_NUM / 2) {
            g_scope_cfg.trigger_level_mv = g_scope_cfg.ch1_div_mv * (SCOPE_TIME_DIV_NUM / 2 - 1) - g_scope_cfg.ch1_gnd_mv;
        }
        if (g_scope_cfg.trigger_level_mv + g_scope_cfg.ch1_gnd_mv <= -g_scope_cfg.ch1_div_mv * SCOPE_TIME_DIV_NUM / 2) {
            g_scope_cfg.trigger_level_mv = -g_scope_cfg.ch1_div_mv * (SCOPE_TIME_DIV_NUM / 2 - 1) - g_scope_cfg.ch1_gnd_mv;
        }
    }
}

int scope_helper_buffer_get_rate_by_div(uint32_t time_div_us)
{ 
    int rate = SCOPE_ADC_BUFFER_POINTS * 1000000.0 / (time_div_us * SCOPE_TIME_DIV_NUM * 2);

    if (rate > SCOPE_MAX_SAMPLE_RATE) {
        rate = SCOPE_MAX_SAMPLE_RATE;
    }
    return rate;
}

static bool scope_snap_helper_div_valid(uint32_t time_div_us)
{
    int rate = scope_helper_buffer_get_rate_by_div(time_div_us);

    if (rate <= SCOPE_MIN_SAMPLE_RATE) {
        return false;
    }
    return true;
}

void scope_helper_correct_time_div(void)
{
    int index = scope_helper_value_to_index_round_up(g_scope_cfg.time_div_us);
    int div = scope_helper_index_to_value(index);

    while (scope_snap_helper_div_valid(div) == false) {
        index--;
        div = scope_helper_index_to_value(index);
    }
    g_scope_cfg.time_div_us = div;
    g_scope_cfg.rate = scope_helper_buffer_get_rate_by_div(g_scope_cfg.time_div_us);
}

static void scope_helper_proc_set_sample_rate(char *value)
{
    uint32_t rate = atoi(value);

    scope_hw_set_sample_rate(rate);
    log_printf("SampleRate: %d div: %d\n", g_scope_cfg.rate, div);
}
HTTPD_CGI_PARAM_DEFINE("SampleRate", scope_helper_proc_set_sample_rate);

void scope_helper_proc_set_ch0_coupling(char *value)
{
    if (!strcmp(value, "DC")) {
        scope_hw_set_ch_coupling(0, SCOPE_COUPLING_DC);
    } else {
        scope_hw_set_ch_coupling(0, SCOPE_COUPLING_AC);
    }
    log_printf("Ch0Coupling: %s\n", value);
}
HTTPD_CGI_PARAM_DEFINE("Ch0Coupling", scope_helper_proc_set_ch0_coupling);

void scope_helper_proc_set_ch1_coupling(char *value)
{
    if (!strcmp(value, "DC")) {
        scope_hw_set_ch_coupling(1, SCOPE_COUPLING_DC);
    } else {
        scope_hw_set_ch_coupling(1, SCOPE_COUPLING_AC);
    }
    log_printf("Ch1Coupling: %s\n", value);
}
HTTPD_CGI_PARAM_DEFINE("Ch1Coupling", scope_helper_proc_set_ch1_coupling);

static void scope_helper_proc_ch0_scale_ctrl(char *value)
{
    g_scope_cfg.ch0_scale = atoi(value);
    scope_hw_update_ch_scale();
    log_printf("Ch0Scale: %d\n", g_scope_cfg.ch0_scale);
}
HTTPD_CGI_PARAM_DEFINE("Ch0Scale", scope_helper_proc_ch0_scale_ctrl);

static void scope_helper_proc_ch1_scale_ctrl(char *value)
{
    g_scope_cfg.ch1_scale = atoi(value);
    scope_hw_update_ch_scale();
    log_printf("Ch1Scale: %d\n", g_scope_cfg.ch1_scale);
}
HTTPD_CGI_PARAM_DEFINE("Ch1Scale", scope_helper_proc_ch1_scale_ctrl);

static void scope_helper_proc_ch0_div_add(char *value)
{
    int index = scope_helper_value_to_index_round_up(g_scope_cfg.ch0_div_mv);

    g_scope_cfg.ch0_div_mv = scope_helper_index_to_value(index + 1);
    if (g_scope_cfg.ch0_div_mv > 50000) {
        g_scope_cfg.ch0_div_mv = 50000;
    }
    scope_hw_auto_ch_scale();
    log_printf("Ch0DivAdd: %d\n", g_scope_cfg.ch0_div_mv);
}
HTTPD_CGI_PARAM_DEFINE("Ch0DivAdd", scope_helper_proc_ch0_div_add);

static void scope_helper_proc_ch0_div_dec(char *value)
{
    int index = scope_helper_value_to_index_round_up(g_scope_cfg.ch0_div_mv);

    g_scope_cfg.ch0_div_mv = scope_helper_index_to_value(index - 1);  
    if (g_scope_cfg.ch0_div_mv < 20) {
        g_scope_cfg.ch0_div_mv = 20;
    }
    scope_helper_correct();
    scope_hw_auto_ch_scale();
    log_printf("Ch0DivDec: %d\n", g_scope_cfg.ch0_div_mv);
}
HTTPD_CGI_PARAM_DEFINE("Ch0DivDec", scope_helper_proc_ch0_div_dec);

static void scope_helper_proc_ch1_div_add(char *value)
{
    int index = scope_helper_value_to_index_round_up(g_scope_cfg.ch1_div_mv);

    g_scope_cfg.ch1_div_mv = scope_helper_index_to_value(index + 1);
    if (g_scope_cfg.ch1_div_mv > 50000) {
        g_scope_cfg.ch1_div_mv = 50000;
    }
    scope_hw_auto_ch_scale();
    log_printf("Ch1DivAdd: %d\n", g_scope_cfg.ch1_div_mv);
}
HTTPD_CGI_PARAM_DEFINE("Ch1DivAdd", scope_helper_proc_ch1_div_add);

static void scope_helper_proc_ch1_div_dec(char *value)
{
    int index = scope_helper_value_to_index_round_up(g_scope_cfg.ch1_div_mv);

    g_scope_cfg.ch1_div_mv = scope_helper_index_to_value(index - 1);
    if (g_scope_cfg.ch1_div_mv < 20) {
        g_scope_cfg.ch1_div_mv = 20;
    }
    scope_helper_correct();
    scope_hw_auto_ch_scale();
    log_printf("Ch1DivDec: %d\n", g_scope_cfg.ch1_div_mv);
}
HTTPD_CGI_PARAM_DEFINE("Ch1DivDec", scope_helper_proc_ch1_div_dec);

static void scope_helper_proc_hw_set_ch0_gnd(char *value)
{
    g_scope_cfg.ch0_gnd_mv = atoi(value);
    scope_helper_correct();
    log_printf("Ch0Gnd: %d\n", g_scope_cfg.ch0_gnd_mv);
}
HTTPD_CGI_PARAM_DEFINE("Ch0Gnd", scope_helper_proc_hw_set_ch0_gnd);

static void scope_helper_proc_hw_set_ch1_gnd(char *value)
{
    g_scope_cfg.ch1_gnd_mv = atoi(value);
    scope_helper_correct();
    log_printf("Ch1Gnd: %d\n", g_scope_cfg.ch1_gnd_mv);
}
HTTPD_CGI_PARAM_DEFINE("Ch1Gnd", scope_helper_proc_hw_set_ch1_gnd);
